In [1]:
from llvmlite import ir
Build a simple function with a for loop that sum the first N integer, where N is the argument.
In [2]:
m = ir.Module()
In [3]:
fnty = ir.FunctionType(ir.IntType(32), [ir.IntType(32)])
print(fnty)
In [4]:
fn = ir.Function(m, fnty, "count_number")
fn.args[0].name= 'N'
print(fn)
In [5]:
builder = ir.IRBuilder(fn.append_basic_block('entry'))
Initialize variable ct
and out
with 0
In [6]:
out = builder.alloca(ir.IntType(32), name='out')
ct = builder.alloca(ir.IntType(32), name='ct')
builder.store(out.type.pointee(0), out)
builder.store(ct.type.pointee(0), ct)
print(fn)
Populate loop header
In [7]:
loophead = fn.append_basic_block('loop.header')
loopbody = fn.append_basic_block('loop.body')
loopend = fn.append_basic_block('loop.end')
builder.branch(loophead)
builder.position_at_end(loophead)
# loop if ct < arg0
arg0 = fn.args[0]
pred = builder.icmp_signed('<', builder.load(ct), arg0)
builder.cbranch(pred, loopbody, loopend)
print(fn)
Populate loop body
In [8]:
builder.position_at_end(loopbody)
# out += ct
builder.store(builder.add(builder.load(out), builder.load(ct)), out)
# ct += 1
builder.store(builder.add(builder.load(ct), ct.type.pointee(1)), ct)
# jump to loophead
builder.branch(loophead)
print(fn)
Populate loop end
In [9]:
builder.position_at_end(loopend)
builder.ret(builder.load(out))
print(fn)
Visualize CFG
In [10]:
from llvmlite import binding as llvm
dot = llvm.get_function_cfg(fn)
llvm.view_dot_graph(dot)
Out[10]:
Optimize the function
In [11]:
# materialize a LLVM module
mod = llvm.parse_assembly(str(m))
# create optimizer
pm = llvm.create_module_pass_manager()
pmb = llvm.create_pass_manager_builder()
pmb.opt_level = 3 # -O3
pmb.populate(pm)
# optimize
pm.run(mod)
print(mod)
View optimized CFG
In [12]:
dot = llvm.get_function_cfg(mod.get_function(fn.name))
llvm.view_dot_graph(dot)
Out[12]:
Notice LLVM has optimized the looping away.